package com.wgo.precise.client.ui.view.editor;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IReusableEditor;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.editor.IFormPage;

import com.wgo.precise.client.ui.controller.ModelStatus;
import com.wgo.precise.client.ui.controller.Registry;
import com.wgo.precise.client.ui.controller.RequirementPlugin;
import com.wgo.precise.client.ui.controller.listeners.IModelChangeListener;
import com.wgo.precise.client.ui.controller.listeners.IModelUpdateListener;
import com.wgo.precise.client.ui.controller.listeners.ModelItemDeletedListener;
import com.wgo.precise.client.ui.controller.listeners.NewModelItemCreatedListener;
import com.wgo.precise.client.ui.controller.listeners.SessionStatusListener;
import com.wgo.precise.client.ui.model.CategoryWrapper;
import com.wgo.precise.client.ui.model.ClientModelItem;
import com.wgo.precise.client.ui.model.facade.IModelPersistable;
import com.wgo.precise.client.ui.model.facade.INodeParent;
import com.wgo.precise.client.ui.view.editor.dummy.DummyFormPage;
import com.wgo.precise.client.ui.view.editor.dummy.DummyItem;
import com.wgo.precise.client.ui.view.editor.history.HistoryFormPage;
import com.wgo.precise.client.ui.view.editor.properties.PropertiesFormPage;
import com.wgo.precise.client.ui.view.editor.requirementtable.RequirementTableFormPage;
import com.wgo.precise.client.ui.view.facade.IExtendedEditorPart;
import com.wgo.precise.client.ui.view.util.ModelPersistable;


/**
 * @author petterei
 *
 * @version $Id: ModelItemEditor.java,v 1.3 2006-02-06 09:29:08 petterei Exp $
 */
public class ModelItemEditor extends FormEditor implements IReusableEditor, IModelItemFormEditor, IExtendedEditorPart, SessionStatusListener {
	
	private IModelPersistable item = null;
	
	@Override
	public void init(IEditorSite site, IEditorInput input) throws PartInitException {
		super.init(site, input);
		if (getModelInput() instanceof ClientModelItem){
			RequirementPlugin.getInstance().getPreciseSubject().addListener( IModelUpdateListener.class , this );
			RequirementPlugin.getInstance().getPreciseSubject().addListener( IModelChangeListener.class , this );
			RequirementPlugin.getInstance().getPreciseSubject().addListener( NewModelItemCreatedListener.class , this );
			RequirementPlugin.getInstance().getPreciseSubject().addListener( ModelItemDeletedListener.class , this );
			RequirementPlugin.getInstance().getPreciseSubject().addListener( SessionStatusListener.class , this );
		} else {
			RequirementPlugin.getInstance().getPreciseSubject().removeListener( IModelChangeListener.class , this );
			RequirementPlugin.getInstance().getPreciseSubject().removeListener( IModelUpdateListener.class , this );
			RequirementPlugin.getInstance().getPreciseSubject().removeListener( NewModelItemCreatedListener.class , this );
			RequirementPlugin.getInstance().getPreciseSubject().removeListener( ModelItemDeletedListener.class , this );
			RequirementPlugin.getInstance().getPreciseSubject().removeListener( SessionStatusListener.class , this );
		}
		if (null != getModelInput()) {
			RequirementPlugin.getInstance().getEditorWindowManager().addExtendedEditor(this);
		}
	}

	@Override
	public void dispose() {
		super.dispose();
		RequirementPlugin.getInstance().getEditorWindowManager().removeExtendedEditor(this);
		item = null;
		RequirementPlugin.getInstance().getPreciseSubject().removeListener( IModelUpdateListener.class , this );
		RequirementPlugin.getInstance().getPreciseSubject().removeListener( IModelChangeListener.class , this );
		RequirementPlugin.getInstance().getPreciseSubject().removeListener( NewModelItemCreatedListener.class , this );
		RequirementPlugin.getInstance().getPreciseSubject().removeListener( ModelItemDeletedListener.class , this );
		RequirementPlugin.getInstance().getPreciseSubject().removeListener( SessionStatusListener.class , this );
	}

	@Override
	public void close(boolean save) {
		RequirementPlugin.getInstance().getEditorWindowManager().removeExtendedEditor(this);
		super.close(save);
	}

	@Override
	public void addPages() {
		try {
			if (getModelInput() instanceof ClientModelItem) {
				addPage(new PropertiesFormPage(this));
				addPage(new HistoryFormPage(this));
				IFormPage page = setActivePage(PropertiesFormPage.PAGE_ID, item);
				page.getManagedForm().getForm().getBody().layout(true);
				if (getModelInput() instanceof CategoryWrapper) {
					addPage(new RequirementTableFormPage(this));
				}
				return;
			}
			if (getModelInput() instanceof DummyItem) {
				addPage(new DummyFormPage(this));
				setActivePage(DummyFormPage.PAGE_ID, item);
				return;
			}
			if (0 == pages.size()) {
				RequirementPlugin.log(new ModelStatus(IStatus.WARNING, "No page(s) added to editor. Adding dummy-page and closing."));
				addPage(new DummyFormPage(this));
				getSite().getShell().getDisplay().asyncExec(new CloseEditorRunnable(this));
//				new Thread(new CloseEditorRunnable(this)).start();
			}
////			addPage(0, new PropertiesFormEditorPart(), input);
//			if (getModelInput() instanceof IPropertyDefinitionContainer) {
////				addPage(new UsertypesFormPage(this));
//				//				addPage(new UserTypesEditorPage(this));
//			}
//			if (getModelInput() instanceof IRequirementTableProvider) {
////				addPage(new TableEditorPart(), getEditorInput());
//			}
		} catch (PartInitException e) {
			RequirementPlugin.log(new Status(IStatus.ERROR, Registry.PLUGIN_ID, IStatus.OK, "Could not open editor..", e));
		}
	}

	/**
	 * @see org.eclipse.ui.part.EditorPart#setInput(org.eclipse.ui.IEditorInput)
	 */
	@Override
	public void setInput(IEditorInput input) {
		super.setInput(input);
		ModelPersistable modelElement = (ModelPersistable) getEditorInput().getPersistable();
        if (null != modelElement) {
            this.item = modelElement.getItem();
        	updateMetaInformation();
        } else {
			RequirementPlugin.log(new ModelStatus(IStatus.WARNING, getClass().getSimpleName() + ": No valid object in input." ));
        }
	}

	/**
	 * @see com.wgo.precise.client.ui.view.editor.IModelItemFormEditor#getModelInput()
	 */
	public IModelPersistable getModelInput() {
		return item;
	}


	/**
	 * @see com.wgo.precise.client.ui.view.facade.IModelUpdateListener#onModelUpdate(IModelPersistable)
	 */
	public void onModelUpdate(IModelPersistable targetUpdateItem) {
		updateMetaInformation();
		for (Object o : pages) {
			if (o instanceof IModelUpdateListener) {
				((IModelUpdateListener)o).onModelUpdate(targetUpdateItem);
			}
		}
	}

	private void updateMetaInformation(){
		if (null != getModelInput()) {
			setPartName(getModelInput().getText());
			setContentDescription(getModelInput().getToolTipText());
			setTitleToolTip(getModelInput().getToolTipText());
			Image image = getModelInput().getImage();
			if (null != image) {
				setTitleImage(image);
			}
		} else {
			RequirementPlugin.log(new ModelStatus(IStatus.ERROR, this.getClass().getSimpleName()+ " Has no valid input" ));
		}
	}
	public void onModelChange(IModelPersistable targetChangeItem) {
		for (Object o : pages) {
			if (o instanceof IModelChangeListener) {
				((IModelChangeListener)o).onModelChange(targetChangeItem);
			}
		}
		getActivePageInstance().getManagedForm().getForm().getBody().layout(true);
	}

	public void onModelItemDeleted(IModelPersistable deletedItem, INodeParent parent) {
		for (Object o : pages) {
			if (o instanceof ModelItemDeletedListener) {
				ModelItemDeletedListener listener = (ModelItemDeletedListener) o;
				listener.onModelItemDeleted(deletedItem, parent);
			}
		}
//		getActivePageInstance().getManagedForm().getForm().getBody().layout(true);
		getActivePageInstance().getManagedForm().reflow(true);
	}

	public void onNewModelItemCreated(IModelPersistable createdItem) {
		for (Object o : pages) {
			if (o instanceof NewModelItemCreatedListener) {
				NewModelItemCreatedListener listener = (NewModelItemCreatedListener) o;
				listener.onNewModelItemCreated(createdItem);
			}
		}
//		getActivePageInstance().getManagedForm().getForm().getBody().layout(true);
		getActivePageInstance().getManagedForm().reflow(true);
	}


	/* (non-Javadoc)
	 * @see com.wgo.precise.client.ui.controller.listeners.SessionStatusListener#onSave()
	 */
	public void onSave() {
		for (Object page : pages) {
			if (page instanceof SessionStatusListener) {
				((SessionStatusListener) page).onSave();
			}
		}
	}

	/**
	 * @deprecated Save not triggered here, use remato.client.controller.ClientSession.saveAll()
	 */
	@Deprecated // Save not triggered here, thus should not be used
	@SuppressWarnings("unused") // Method not used, thus parameters not used
	@Override
	public void doSave(IProgressMonitor monitor) {}

	@Override
	public void doSaveAs() {}

	@Override
	public boolean isSaveAsAllowed() {
		return false;
	}

	public void inputChanged() {
		for (Object o : pages) {
			int i = pages.indexOf(o);
			removePage(i);
		}
		addPages();
	}

	/**
	 * @see org.eclipse.ui.part.MultiPageEditorPart#setFocus()
	 */
	@Override
	public void setFocus() { 
		int pageIndex = getActivePage();
		if (0 <= pageIndex 
				&& getPageCount() >= pageIndex 
				&& pages.get(pageIndex) instanceof AbstractFormPage) {
			((AbstractFormPage)pages.get(pageIndex)).refresh(); // TODO: consider use FormPage.setFocus() instead and let refresh() be called from there to create less plugin-related connectivity 
		}
		super.setFocus();
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return super.toString() + " (" + getTitle() + " " + getTitleToolTip() + ")";
	}
	
}
class CloseEditorRunnable implements Runnable {
	private IEditorPart part = null;
	public CloseEditorRunnable(IEditorPart part) {
		this.part = part;
	}
	public void run() {
		try {
			RequirementPlugin pluign = RequirementPlugin.getInstance();
			IWorkbench bench = pluign.getWorkbench();
			IWorkbenchWindow window = bench.getActiveWorkbenchWindow();
			IWorkbenchPage page = window.getActivePage();
			page.closeEditor(part, false);
		} catch (Exception e) {
			RequirementPlugin.log(e, "error closing" );
		}
	}
}